package cn.edu.fudan.data;

import cn.edu.fudan.tools.SimilarityMeasure;
import cn.edu.fudan.type.DataItem;
import org.apache.log4j.Logger;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;

public class HandleDistance {
	private Logger logger = Logger.getLogger(HandleDistance.class);
	
	public List<List<DataItem>> calDistance(List<List<Double>> map_A, List<List<Double>> map_B, int flag){
		SimilarityMeasure similarityMeasure = new SimilarityMeasure();
		List<List<DataItem>> map_distance = new ArrayList<>();
		
		for(int i = 0; i < map_A.size(); i ++){
			List<DataItem> distances = new ArrayList<>();
			for(int j = 0; j < map_A.size(); j ++){
				double distance = similarityMeasure.calEucliDistance(map_A.get(i), map_A.get(j));
				DataItem di = new DataItem();
				if(flag == 0){
					di.setTimestamp(111111);
				}else if(flag == 1){
					di.setTimestamp(j);
				}
				di.setValue(distance);
				distances.add(di);
			}
			for(int j = 0; j < map_B.size(); j ++){
				double distance = similarityMeasure.calEucliDistance(map_A.get(i), map_B.get(j));
				DataItem di = new DataItem();
				if(flag == 1){
					di.setTimestamp(111111);
				}else if(flag == 0){
					di.setTimestamp(j);
				}
				di.setValue(distance);
				distances.add(di);
			}
			Collections.sort(distances, new Comparator<DataItem>() {

				@Override
				public int compare(DataItem o1, DataItem o2) {
					// TODO Auto-generated method stub
					if(o1.getValue() > o2.getValue()){
						return 1;
					}else if(o1.getValue() < o2.getValue()){
						return -1;
					}
					return 0;
				}
			});
			map_distance.add(distances);				
		}
		return map_distance;
	}
	
	public double calAccuracy(List<List<Double>> map_A, List<List<Double>> map_B, List<List<Double>> test_A, int K){
		SimilarityMeasure similarityMeasure = new SimilarityMeasure();
		List<List<DataItem>> map_distance = new ArrayList<>();
		
		for(int i = 0; i < test_A.size(); i ++){     //好像是计算mapA与test_A的距离和mapB与test_B距离把他们放到一个list当中，并排序
			List<DataItem> distances = new ArrayList<>();
			for(int j = 0; j < map_A.size(); j ++){
				double distance = similarityMeasure.calEucliDistance(test_A.get(i), map_A.get(j));
				DataItem di = new DataItem();
				di.setTimestamp(1);
				di.setValue(distance);
				distances.add(di);
			}
			for(int j = 0; j < map_B.size(); j ++){
				double distance = similarityMeasure.calEucliDistance(test_A.get(i), map_B.get(j));
				DataItem di = new DataItem();
				di.setTimestamp(0);
				di.setValue(distance);
				distances.add(di);
			}
			Collections.sort(distances, new Comparator<DataItem>() {  //这是干嘛的？

				@Override
				public int compare(DataItem o1, DataItem o2) {
					// TODO Auto-generated method stub
					if(o1.getValue() > o2.getValue()){
						return 1;
					}else if(o1.getValue() < o2.getValue()){
						return -1;
					}
					return 0;
				}
			});
			map_distance.add(distances);				
		}
		
		int posi = 0;
		for(int i = 0; i < map_distance.size(); i ++){
			int count_posi = 0;
			for(int j = 0; j < (K>map_distance.size()? map_distance.size():K); j ++){    //这里的K是KNN的K
				Long num = map_distance.get(i).get(j).getTimestamp();
				if(num == 1){
					count_posi ++;
				}
			}
			if(count_posi > K/2){
				posi ++;
			}
		}
		
		logger.info("positive patter: "+posi+"\t"+"all: "+map_distance.size()+"\t"+posi/(double)map_distance.size());
		
		return posi/(double)map_distance.size();		
	}
	
	public List<List<DataItem>> calDistance(List<List<Double>> map_A, List<List<Double>> map_B, List<List<Double>> test_A){

		SimilarityMeasure similarityMeasure = new SimilarityMeasure();
		List<List<DataItem>> map_distance = new ArrayList<>();
		
		for(int i = 0; i < test_A.size(); i ++){
			List<DataItem> distances = new ArrayList<>();
			for(int j = 0; j < map_A.size(); j ++){
				double distance = similarityMeasure.calEucliDistance(test_A.get(i), map_A.get(j));
				DataItem di = new DataItem();
				di.setTimestamp(1);
				di.setValue(distance);
				distances.add(di);
			}
			for(int j = 0; j < map_B.size(); j ++){
				double distance = similarityMeasure.calEucliDistance(test_A.get(i), map_B.get(j));
				DataItem di = new DataItem();
				di.setTimestamp(0);
				di.setValue(distance);
				distances.add(di);
			}
			Collections.sort(distances, new Comparator<DataItem>() { //按值排序

				@Override
				public int compare(DataItem o1, DataItem o2) {
					// TODO Auto-generated method stub
					if(o1.getValue() > o2.getValue()){
						return 1;
					}else if(o1.getValue() < o2.getValue()){
						return -1;
					}
					return 0;
				}
			});
			map_distance.add(distances);			//统计得出针对每段testA的feature对mapA和mapB中每段的欧式距离，并根据值升序排序
													// ，但是需要标记每个值是testA与mapA得出的还是testB与mapB得出的
													//然后对于每个testA中的feature得到一组有序值（一段testA与testA和testB各段的距离 ）
													//这样就可以得到当我们取到前K个值的时候，可以知道，testA与mapA和testA和mapB分别有多少，
													//因为只要统计前K个timestamp中的0和1的个数就行了。
		}
		
		return map_distance;
	}
	
	public double  calAccuracy(List<List<Double>> map_A, List<List<Double>> map_B, List<List<Double>> test_A, List<List<Double>> test_B, int K){
		List<List<DataItem>> map_distance = new ArrayList<>();
		
		map_distance.addAll(calDistance(map_A, map_B, test_A));
		map_distance.addAll(calDistance(map_B, map_A, test_B));//这里是不是计算了两遍？并没有，因为第一句是说的是A的观测值，第二句是B的观测值
		
		
		int posi = 0;
		for(int i = 0; i < map_distance.size(); i ++){ //map_distance
			int count_posi = 0;
			for(int j = 0; j < (K>map_distance.size()? map_distance.size():K); j ++){
				Long num = map_distance.get(i).get(j).getTimestamp();
				if(num == 1){
					count_posi ++; //
				}
			}
			if(count_posi > K/2){  //map_distance.size>K/2
				posi ++;
			}
		}
		
//		logger.info("positive patter: "+posi+"\t"+"all: "+map_distance.size()+"\t"+posi/(double)map_distance.size());
		
		return posi/(double)map_distance.size();		
	}
	
	
	public double calAccuracy(List<List<DataItem>> map_distance, int N){
		
		int posi = 0;
		for(int i = 0; i < map_distance.size(); i ++){
			int count_posi = 0;
			for(int j = 0; j < N; j ++){
				Long num = map_distance.get(i).get(j).getTimestamp();
				if(num == 111111){
					count_posi ++;
				}
			}
			if(count_posi > N/2){
				posi ++;
			}
		}
//		logger.info("positive patter: "+posi+"\t"+"all: "+map_distance.size()+"\t"+posi/(double)map_distance.size());
		
		return posi/(double)map_distance.size();
	}
	
	public double analyzeDistance(List<List<DataItem>> map_distance, int N){
//		Map<Long, Integer> countNum = new HashMap<Long, Integer>();
//		List<CountNum> count = new ArrayList<>();
		int posi = 0;
		for(int i = 0; i < map_distance.size(); i ++){
			int count_posi = 0;
			for(int j = 0; j < N; j ++){
				Long num = map_distance.get(i).get(j).getTimestamp();
//				if(countNum.containsKey(num)){
//					int n = countNum.get(num) + 1;
//					countNum.put(num, n);
//				}else{
//					countNum.put(num, 1);
//				}
				if(num == 111111){
					count_posi ++;
				}
			}
//			logger.info(count_posi);
			if(count_posi > N/2){
				posi ++;
//				logger.info(i);
			}
		}
		logger.info("positive patter: "+posi+"\t"+"all: "+map_distance.size()+"\t"+posi/(double)map_distance.size());
//		for(Map.Entry<Long, Integer> entry : countNum.entrySet()){
//			CountNum cNum = new CountNum();
//			cNum.setNum(entry.getKey());
//			cNum.setCount(entry.getValue());
//			count.add(cNum);
//		}
//		Collections.sort(count, new Comparator<CountNum>() {
//			@Override
//			public int compare(CountNum o1, CountNum o2) {
//				return o2.getCount()-o1.getCount();
//			}
//		});
		return posi/(double)map_distance.size();
	}
}
